import React, {Component} from 'react';
import {observable, action, computed} from 'mobx';
import BaseStore from '../BaseStore';
import moment from 'moment';
import * as api from '../../apis/sign';
import {Tools, Bubble} from 'weaver-mobile';
import {Form, MapPage} from 'weaver-mobile-page';
import {forwardViewForm} from '../../../workflowForm/util/forwardPage';
import MapUtil from '../../util/mapUtil';
import {getDeviceInfo, getLocation, checkFaceId, getBrowserType} from '../../util/jemUtil';
import isEmpty from 'lodash/isEmpty';
import has from 'lodash/has';

const getLabel = Tools.getLabel;
// const getCurrentPosition = MapPage.getCurrentPosition;

class SignStoreV2 extends BaseStore{
    //#region layout
    @observable _showSchedual = false;
    @computed get showSchedual(){return this._showSchedual}
    set showSchedual(v){this._showSchedual = v}

    @action setShowSchedual = () => {
        this.showSchedual = !this.showSchedual;
    }
    //#endregion

    //#region arguments
    convertStatus = v => {
        switch (v) {
            case '0':
                return {
                    label: getLabel('225', '正常'),
                    className: 'normal'
                };
            case '1':
                return {
                    label: getLabel('20081', '迟到'),
                    className: 'abnormal'
                };
            case '2':
                return {
                    label: getLabel('20082', '早退'),
                    className: 'abnormal'
                };
            case '3':
                return {
                    label: getLabel('20085', '旷工'),
                    className: 'abnormal'
                };
            case '4':
                return {
                    label: getLabel('20086', '漏签'),
                    className: 'abnormal'
                };
            case '5':
                return {
                    label: getLabel('26198', '外勤'),
                    className: 'abnormal'
                };
            case 'auto_card':
                return {
                    label: getLabel('522591','自动打卡'),
                    className: 'autoSign'
                };
            default:
                return {
                    label: '',
                    className: ''
                };
        }
    }

    @computed get hasRangeCheck(){//是否启用考勤点打卡或
        const {locationcheck, wificheck} = this.baseInfo;
        return locationcheck || wificheck;
    }

    @computed get faceIdEnable(){//是否需要人脸识别
        const {locationcheck, locationfacecheck, wificheck, wififacecheck} = this.baseInfo;
        return getBrowserType() == 'emobile' && ((locationcheck && locationfacecheck == '1') || (wificheck && wififacecheck == '1'));
    }
    //#endregion

    //#region 地图相关
    @observable mapUtil = new MapUtil();

    @action onMapTypeChangeHandle = async type => {
        //call change map type
        api.resetUserMap({user_last_map: type});
    }
    //#endregion

    //#region 模块初始化 
    @action clearData = async () => {
    }

    //1.获取基础信息 2.获取打卡时间轴 3.获取考勤范围 4.判断是否在考勤范围
    @action init = async () => {
        const data = await this.getButtonBaseInfo();
        const {showbutton} = data;
        this.clearData();
        //test
        // this.getOsInfo();
        // this.Toast.loading('loading', 0);
        if(showbutton != '0'){
            this.getButtons();
            this.hasRangeCheck && this.getLocationWifiInfo();
            this.getOutButtons();
        }
        // this.Toast.hide();
    }
    //#endregion

    //#region 获取基础信息
    monitor = null;//刷新当前打卡时间计时器
    @observable _currTime = moment();//刷新当前打卡时间
    @computed get currTime(){return this.toJS(this._currTime)}
    set currTime(v){this._currTime = v}

    @observable _baseInfo = {};//基础信息
    @computed get baseInfo(){return this.toJS(this._baseInfo)}
    set baseInfo(v){this._baseInfo = v}

    @action getButtonBaseInfo = async () => {
        const data = await api.getButtonBaseInfo();
        if(data.status == '1' || data.status == null){
            delete data.status;
            this.baseInfo = data;
            const {timemillis} = data;
            this.currTime = (timemillis != null ? moment(new Date(timemillis)) : moment());
            this.clearMonitor();
            this.monitor = setInterval(() => {this.currTime = this.currTime.add(1, 'seconds')}, 1000);
        }
        return data;
    }

    @action clearMonitor = () => {this.monitor != null && clearInterval(this.monitor)}
    //#endregion
    
    //#region 获取打卡时间轴数据
    @observable _timeLineInfo = {};
    @computed get timeLineInfo(){return this.toJS(this._timeLineInfo)}
    set timeLineInfo(v){this._timeLineInfo = v}

    @action getButtons = async () => {
        const data = await api.getButtons();
        if(data.status == '1' || data.status == null){
            delete data.status;
            this.timeLineInfo = data;
        }
    }
    //#endregion

    //#region 获取考勤范围数据
    @observable _locationAndWifiInfo = {};
    @computed get locationAndWifiInfo(){return this.toJS(this._locationAndWifiInfo)}
    set locationAndWifiInfo(v){this._locationAndWifiInfo = v}

    @action getLocationWifiInfo = async (showWifiList = '0') => {
        const data = await api.getLocationWifiInfo({showWifiList});
        if(data.status == '1' || data.status == null){
            delete data.status;
            this.locationAndWifiInfo = data;
        }
    }
    //#endregion

    //#region 获取设备信息
    deviceInfo = {};
    //#endregion

    //#region 获取定信息
    @observable _locationInfo = {};
    @computed get locationInfo(){return this.toJS(this._locationInfo)}
    set locationInfo(v){this._locationInfo = v}

    @computed get hasLocationInfo(){
        const {longitude, latitude} = this.locationInfo;
        return longitude != null && longitude != '' && latitude != null && latitude != '';
    }

    @action onLocationChangedHandle = async locationInfo => {
        if(locationInfo.status == '1' && isEmpty(locationInfo.address)){
            const regeoData = await this.mapUtil.regeo(locationInfo);
            Object.assign(locationInfo, regeoData);
        }
        this.locationInfo = locationInfo;
    }

    @action relocation = async callback => {
        this.getOutButtons();
        callback && callback();
    }
    //#endregion

    //#region 两点间距离计算
    @computed get distance(){
        this.mapInited;
        let result;
        const {longitude, latitude} = this.locationInfo;
        const {locationInfo: locationSetting} = this.locationAndWifiInfo;
        const {locationcheck, locations} = locationSetting || {};
        result = {locationcheck};
        if(longitude == null || longitude == '' || latitude == null || latitude == '' || isEmpty(locationSetting))
            return result;

        let dis, shortestPosition;
        const R = 6378137; //单位 米
        if(locationcheck && locations && locations.length > 0){
            locations.map(location => {
                try{
                    let tmp;
                    if(this.amap){
                        const a = new window.AMap.LngLat(Number(longitude), Number(latitude));
                        const b = new window.AMap.LngLat(Number(location.longitude), Number(location.latitude));
                        tmp = a.distance(b);    
                    }else{
                        const lon1 = Number(longitude) * Math.PI / 180;
                        const lat1 = Number(latitude) * Math.PI / 180;

                        const lon2 = Number(location.longitude) * Math.PI / 180;
                        const lat2 = Number(location.latitude) * Math.PI / 180;


                        const deltaLat = lat1 - lat2
                        const deltaLon = lon1 - lon2


                        const step1 = Math.pow(Math.sin(deltaLat / 2), 2) + Math.cos(lat2) * Math.cos(lat1) * Math.pow(Math.sin(deltaLon / 2), 2);
                        const step2 = 2 * Math.atan2(Math.sqrt(step1), Math.sqrt(1 - step1));
                        tmp = step2 * R;
                    }
                    if(dis == null || dis > tmp){
                        dis = tmp;
                        shortestPosition = location;
                    }
                }catch(e){
                    Bubble.error(getLabel('504567','获取考勤点失败'));
                }
            });
            Object.assign(result, {
                dis,
                shortestPosition,
                isOutSign: dis > Number(shortestPosition.checkscope)
            })
        }

        return result;
    } 
    //#endregion

    //#region 判断是否在考勤范围
    @observable _checkRangeResult = {};
    @computed get checkRangeResult(){return this.toJS(this._checkRangeResult)}
    set checkRangeResult(v){this._checkRangeResult = v}

    @computed get iconProps(){
        const props = {size: 'xs', color: '#E5A057', type: 'remind'}
        this.checkRangeResult.status && Object.assign(props, {color: '#25E413', type: 'check-circle'})
        return props;
    }

    @computed get outSignValid(){
        const {status, outsidesign} = this.checkRangeResult;
        return !status && outsidesign == '1' && this.hasRangeCheck;
    }

    @action getOutButtons = async () => {
        this.Toast.loading('loading', 0);
        const result = {status: this.hasRangeCheck ? '1' : '-1'};//status:-1 即为考勤范围验证失败
        this.deviceInfo = await getDeviceInfo();
        this.locationInfo = await getLocation(this.mapUtil, this.onLocationChangedHandle);

        if(this.hasRangeCheck){//如果未启用考勤点打卡或wifi打卡，则不需要进行考勤饭魏验证
            const params = {locationshowaddress: this.baseInfo.locationshowaddress};
            try{
                const {longitude, latitude, status: locationStatus} = this.locationInfo;
                locationStatus == '1' && Object.assign(params, {longitude, latitude});
            }catch(e){}

            try{
                const {SSID: sid, BSSID: mac, deviceId, networkType, status: deviceStatus} = this.deviceInfo;
                deviceStatus == '1' && Object.assign(params, {sid, mac, deviceId, networkType});
            }catch(e){}

            const data = await api.getOutButtons(params);
            if(data.status == '1'){
                const {isrange, rangekey, rangename, failkey, outsidesign, locationid} = data;
                const status = (isrange == '1');
                let message = '';
                const iconProps = {
                    size: 'xs',
                    color: '#E5A057',
                    type: 'remind'
                }
                if(status){
                    message = `${getLabel('500507','已进入考勤范围')} ${rangename}`;
                    Object.assign(iconProps, {color: '#25E413', type: 'check-circle'});
                }else{
                    message = getLabel('500508','当前不在考勤范围内');
                }
                this.checkRangeResult = {message, failkey, rangekey, outsidesign, locationid, iconProps, status};
                Object.assign(result, {status: status ? '1' : '-1'});
            }else{
                Bubble.error(data.message);
                Object.assign(result, {status: '0'});
            }
        }
        this.Toast.hide();
        return result;
    }
    //#endregion

    //#region 打卡按钮点击事件
    @action callSign = async (data, callback) => {
        this.Toast.loading('loading', 0);
        let flag = true;
        if(this.faceIdEnable){//判断是否开启人脸识别
            const checkData = await checkFaceId('faceID');//人脸识别验证
            flag = (checkData.status == '1');
        }
        if(!flag) {
            this.Toast.hide();
            return;
        }
        
        let status = !this.hasRangeCheck ? '1' : -1;
        if(status == '-1'){
            const outBtnData = await this.getOutButtons();
            status = outBtnData.status;
        }
        
        switch(status){
            case '1':
                const params = {...data};

                const {locationshowaddress} = this.baseInfo;
                Object.assign(params, {locationshowaddress});

                const {status: locationStatus, longitude, latitude, address: position} = this.locationInfo;
                locationStatus == '1' && Object.assign(params, {longitude, latitude, position});

                const {locationid} = this.checkRangeResult;
                Object.assign(params, {locationid});

                const {status: deviceInfoStatus, SSID: sid, BSSID: mac, deviceId} = this.deviceInfo;
                deviceInfoStatus == '1' && Object.assign(params, {sid, mac, deviceId, deviceInfo: JSON.stringify(this.deviceInfo)});

                this.browserType && Object.assign(params, {browser: this.browserType});
                
                const data = await api.punchButton(params);
                if(data.status === '1'){
                    if(data.message && data.message.trim().length >0){
                        if(data.success === '1'){
                            Bubble.success(data.message);
                        }else{
                            Bubble.warning(data.message);
                        }
                    }else if(['1', '2'].indexOf(data.kqstatus) > -1){
                        Bubble.warning(getLabel(512595, '您的考勤数据异常，如有需要请提交考勤流程'));
                    }
                    if(callback)
                        callback();
                    else
                        this.getButtons();
                }else{
                    Bubble.error(data.message);
                }
                break;
            case '-1':
                const {outsidesign, failkey} = this._checkRangeResult;
                if(outsidesign == '1'){
                    this.showAlert({
                        title: failkey == 'position' ? getLabel('500510','地理位置不在考勤范围内') : getLabel('507524','WIFI不在考勤范围内'),
                        message: getLabel('500511','您是否要转入外勤打卡？'),
                        okLabel: getLabel('500503','外勤打卡'),
                        cancelLabel: getLabel('500512','不需要'),
                        onOk: () => {
                            this.redirectToOutsideSignApp();
                        },
                        onCancel: () => {}
                    });
                }else{
                    this.showAlert({
                        title: failkey == 'position' ? getLabel('500510','地理位置不在考勤范围内') : getLabel('507524','WIFI不在考勤范围内'),
                        message: getLabel('504701','无法完成考勤打卡'),
                        okLabel: getLabel(33703, '确定'),
                        onOk: () => {
                        },
                        showCancel: false
                    });
                }
                break;
        }
        this.Toast.hide();
    }

    //跳转外勤应用,考勤入口页覆写该函数
    @action redirectToOutsideSignApp = () => {}

    //查看考勤范围
    @action showLocationRangeView = (data, callback) => {
        this.selectedSignData = data;
        callback && callback();
    }
    //#endregion

    //#region 获取异常流程列表
    @action showWorkflow = async () => {
        const data = await api.getWorkflowList();
        const buttons = data.result.map(d => ({
            content: d.title,
            source: d,
            onClick: () => forwardViewForm({iscreate:"1", workflowid: d.wfid})
        }))
        buttons.push({
            content: getLabel(32694, '取消'),
            onClick: () => {
            }
        });
        this.showActionSheetWithOptions({
            message: getLabel('500509','请选择你需要提交的流程'),
            buttons
        })
    }
    //#endregion

    //#region 自动打卡设置
    @observable formStore = new Form.Store({route: '/sign/setting'});

    @action getAutoEMSet = async () => {
        const data = await api.getAutoEMSet();
        if(data.status == 1){
            this.formStore.initForm(data.formField, '/sign/setting');
        }
    }

    @action onFieldChangeHandle = async (condition, value) => {
        this.formStore.onChange(condition, value);
        const data = await api.saveAutoEMSet(this.formStore.formParams);
        if(data.status != "1"){
            Bubble.error(data.message);
        }
    }
    //#endregion
}

export const signStoreV2 = new SignStoreV2();